package hit.core;

import java.util.Date;
import java.util.Iterator;
import java.util.Set;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;

public class ItemIndexTest {
	
	private ItemIndex items;
	private ProductContainer container1;
	private ProductContainer container2;
	private Item item1;
	private Item item2;
	private Product product1;
	private Product product2;
	private Barcode barcode1;
	private Barcode barcode2;

	@Before
	public void setUp() throws Exception {
		items = HomeInventoryTracker.GetEmptyInstance().GetItemIndex();
		
		container1 = new StorageUnit("Under A Rock");
		container2 = new ProductGroup("Creepy Crawlies");
		((ProductGroup) container2).SetParentContainer(container1);
		
		product1 = new Product();
		product1.SetCreation(new Date());
		product1.SetBarcode(new Barcode("036725604919"));
		product1.SetDescription("Testing");
		product1.SetShelfLife(3);
		product1.SetSize(new Size(2, Size.Unit.COUNT));
		product1.SetThreeMonth(10);
		
		product2 = new Product();
		product2.SetCreation(new Date());
		product2.SetBarcode(new Barcode("885370395143"));
		product2.SetDescription("Testing");
		product2.SetShelfLife(3);
		product2.SetSize(new Size(2, Size.Unit.COUNT));
		product2.SetThreeMonth(10);
		
		item1 = new Item();
		item1.SetProduct(product1);
		barcode1 = new Barcode("400000123455");
		item1.SetBarcode(barcode1);
		item1.SetContainer(container1);
		
		item2 = new Item();
		item2.SetProduct(product2);
		barcode2 = new Barcode("400000000008");
		item2.SetBarcode(barcode2);
		item2.SetContainer(container2);
	}

	@After
	public void tearDown() throws Exception {
		items = null;
		
		container1 = null;
		container2 = null;
		
		item1 = null;
		item2 = null;
	}
	
	@Test
	public void TestCanAddItem() {
		items.AddItem(item1);
		
		Item item1clone = new Item();
		item1clone.SetProduct(new Product());
		item1clone.SetBarcode(barcode1);
		item1clone.SetContainer(container1);
		
		assertFalse(items.CanAddItem(item1clone));
		assertTrue(items.CanAddItem(item2));
	}
	
	@Test
	public void TestGetByBarcode() {
		items.AddItem(item1);
		items.AddItem(item2);
		
		assertEquals(item1, items.GetItemByBarcode(barcode1));
		assertEquals(item2, items.GetItemByBarcode(barcode2));
	}
	
	@Test
	public void TestGetByContainer() {
		Item item1clone = new Item();
		item1clone.SetProduct(item1.GetProduct());
		item1clone.SetBarcode(new Barcode("400000000015"));
		item1clone.SetContainer(container1);
		
		items.AddItem(item1);
		items.AddItem(item1clone);
		items.AddItem(item2);
		
		Set<Item> itemSet = items.GetItemsByProductContainer(item1.GetContainer());
		assertEquals(itemSet.size(), 2);
		assertTrue(itemSet.contains(item1));
		assertTrue(itemSet.contains(item1clone));
		assertFalse(itemSet.contains(item2));
		
		itemSet = items.GetItemsByProductContainer(item2.GetContainer());
		assertEquals(itemSet.size(), 1);
		assertTrue(itemSet.contains(item2));
		assertFalse(itemSet.contains(item1));
	}
	
	@Test
	public void TestCanRemove() {
		assertFalse(items.CanRemoveItem(item1));
		
		items.AddItem(item1);
		assertTrue(items.CanRemoveItem(item1));
		
		items.RemoveItem(item1);
		assertFalse(items.CanRemoveItem(item1));
	}
	
	@Test
	public void TestRemove() {
		items.AddItem(item1);
		items.AddItem(item2);
		
		items.RemoveItem(item1);
		assertEquals(items.NumRemovedItems(), 1);
		
		assertNull(items.GetItemByBarcode(item1.GetBarcode()));
		assertEquals(item2, items.GetItemByBarcode(item2.GetBarcode()));
	}
	
	@Test 
	public void TestUpdateItem() {
		//test that the barcode changes
		items.AddItem(item1);
		
		Item item1clone = new Item();
		item1clone.SetProduct(new Product());
		item1clone.SetBarcode(new Barcode("400000000015"));
		item1clone.SetContainer(container1);
		
		items.UpdateItem(item1, item1clone);
		assertNull(items.GetItemByBarcode(item1.GetBarcode()));
		assertEquals(items.GetItemByBarcode(item1clone.GetBarcode()), item1clone);
		
		//test that the product container changes
		item1.SetContainer(container2);
		items.UpdateItem(item1clone, item1);
		assertEquals(items.GetItemsByProductContainer(item1clone.GetContainer()).size(), 0);
		assertEquals(items.GetItemsByProductContainer(item1.GetContainer()).size(), 1);
	}
	
	@Test
	public void TestItemIterator() {
		items.AddItem(item1);
		items.AddItem(item2);
		
		Iterator<Item> i = items.GetItemIterator();
		
		//just test the count, as order is not exact
		int count = 0;
		while (i.hasNext()) {
			i.next();
			count++;
		}
		
		assertEquals(2, count);
	}
	
	@Test
	public void TestRemovedItemIterator() {
		items.AddItem(item1);
		items.AddItem(item2);
		items.RemoveItem(item1);
		items.RemoveItem(item2);
		
		Iterator<Item> i = items.GetRemovedItemIterator();
		
		//just test the count, as order is not exact
		int count = 0;
		while (i.hasNext()) {
			count += 1;
			i.next();
		}
		
		assertEquals(2, count);
	}
	
	@Test 
	public void TestCanTransfer() {
		Item item1clone = new Item();
		item1clone.SetProduct(item1.GetProduct());
		item1clone.SetBarcode(new Barcode("400000000015"));
		item1clone.SetContainer(container1);
		
		items.AddItem(item1);
		items.AddItem(item1clone);
		items.AddItem(item2);
		
		assertFalse(items.CanTransferItem(item1, container1, container2));
		assertTrue(items.CanTransferItem(item2, container2, container1));
	}
	
	@Test
	public void TestTransfer() {
		items.AddItem(item1);
		assertEquals(items.GetItemsByProductContainer(container1).size(), 1);
		assertNull(items.GetItemsByProductContainer(container2));
		
		items.TransferItem(item1, container2);
		assertEquals(0, items.GetItemsByProductContainer(container1).size());
		assertEquals(1, items.GetItemsByProductContainer(container2).size());
	}
}
